TIP Sample App/ZoomingTweetImageViewController.m (163 lines of code) (raw):

// // ZoomingTweetImageViewController.m // TwitterImagePipeline // // Created on 2/11/17. // Copyright © 2020 Twitter. All rights reserved. // #import <TwitterImagePipeline/TwitterImagePipeline.h> #import "AppDelegate.h" #import "TweetImageFetchRequest.h" #import "TwitterAPI.h" #import "ZoomingTweetImageViewController.h" @interface ZoomingTweetImageViewController () <UIScrollViewDelegate, TIPImageFetchDelegate> @property (nonatomic, readonly) TweetImageInfo *tweetImageInfo; @end @implementation ZoomingTweetImageViewController { UIScrollView *_scrollView; UIImageView *_imageView; UIProgressView *_progressView; UITapGestureRecognizer *_doubleTapGuestureRecognizer; TIPImageFetchOperation *_fetchOp; } - (instancetype)initWithTweetImage:(TweetImageInfo *)imageInfo { if (self = [self init]) { _tweetImageInfo = imageInfo; } return self; } - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:nil bundle:nil]) { self.navigationItem.title = @"Tweet Image"; } return self; } - (void)viewDidLoad { [super viewDidLoad]; CGSize targetSize = _tweetImageInfo.originalDimensions; const CGFloat scale = [UIScreen mainScreen].scale; if (scale != 1) { targetSize.height /= scale; targetSize.width /= scale; } _progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 4.)]; _progressView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; _progressView.tintColor = [UIColor yellowColor]; _progressView.progress = 0; _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, targetSize.width, targetSize.height)]; _imageView.contentMode = UIViewContentModeScaleAspectFill; _imageView.clipsToBounds = YES; _imageView.backgroundColor = [UIColor grayColor]; _scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds]; _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _scrollView.backgroundColor = [UIColor blackColor]; _doubleTapGuestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapTriggered:)]; _doubleTapGuestureRecognizer.numberOfTapsRequired = 2; _imageView.image = nil; [_imageView addGestureRecognizer:_doubleTapGuestureRecognizer]; _imageView.userInteractionEnabled = YES; _scrollView.delegate = self; _scrollView.minimumZoomScale = 0.01f; // start VERY small _scrollView.maximumZoomScale = 2.0; _scrollView.contentSize = targetSize; [self.view addSubview:_scrollView]; [self.view addSubview:_progressView]; [_scrollView addSubview:_imageView]; [_scrollView zoomToRect:_imageView.frame animated:NO]; _scrollView.minimumZoomScale = _scrollView.zoomScale; // readjust minimum if (_scrollView.minimumZoomScale > _scrollView.maximumZoomScale) { _scrollView.maximumZoomScale = _scrollView.minimumZoomScale; } [self scrollViewDidZoom:_scrollView]; [self _private_load]; } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; [self scrollViewDidZoom:_scrollView]; CGRect frame = _progressView.frame; frame.origin.y = _scrollView.contentInset.top; _progressView.frame = frame; } - (void)_private_load { id<TIPImageFetchRequest> request = [[TweetImageFetchRequest alloc] initWithTweetImage:_tweetImageInfo targetView:_imageView]; _fetchOp = [APP_DELEGATE.imagePipeline operationWithRequest:request context:nil delegate:self]; [APP_DELEGATE.imagePipeline fetchImageWithOperation:_fetchOp]; } #pragma mark Scroll view delegate - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { return _imageView; } - (void)scrollViewDidZoom:(UIScrollView *)scrollView { CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentInset.left - scrollView.contentInset.right - scrollView.contentSize.width) * 0.5f, 0.f); CGFloat offsetY = MAX((scrollView.bounds.size.height - scrollView.contentInset.top - scrollView.contentInset.bottom - scrollView.contentSize.height) * 0.5f, 0.f); _imageView.center = CGPointMake(scrollView.contentSize.width * 0.5f + offsetX, scrollView.contentSize.height * 0.5f + offsetY); } #pragma mark Double tap - (void)doubleTapTriggered:(UITapGestureRecognizer *)tapper { if (tapper.state == UIGestureRecognizerStateRecognized) { if (_scrollView.zoomScale == _scrollView.maximumZoomScale) { [_scrollView setZoomScale:_scrollView.minimumZoomScale animated:YES]; } else { [_scrollView setZoomScale:_scrollView.maximumZoomScale animated:YES]; } } } #pragma mark TIP delegate - (void)tip_imageFetchOperationDidStart:(TIPImageFetchOperation *)op { NSLog(@"starting Zoom fetch..."); } - (void)tip_imageFetchOperation:(TIPImageFetchOperation *)op willAttemptToLoadFromSource:(TIPImageLoadSource)source { NSLog(@"...attempting load from next source: %zi...", source); } - (void)tip_imageFetchOperation:(TIPImageFetchOperation *)op didLoadPreviewImage:(id<TIPImageFetchResult>)previewResult completion:(TIPImageFetchDidLoadPreviewCallback)completion { NSLog(@"...preview loaded..."); _progressView.tintColor = [UIColor blueColor]; _imageView.image = previewResult.imageContainer.image; completion(TIPImageFetchPreviewLoadedBehaviorContinueLoading); } - (BOOL)tip_imageFetchOperation:(TIPImageFetchOperation *)op shouldLoadProgressivelyWithIdentifier:(NSString *)identifier URL:(NSURL *)URL imageType:(NSString *)imageType originalDimensions:(CGSize)originalDimensions { if (_imageView.image) { return NO; } return YES; } - (void)tip_imageFetchOperation:(TIPImageFetchOperation *)op didUpdateProgressiveImage:(id<TIPImageFetchResult>)progressiveResult progress:(float)progress { NSLog(@"...progressive update (%.3f)...", progress); _progressView.tintColor = [UIColor orangeColor]; [_progressView setProgress:progress animated:YES]; _imageView.image = progressiveResult.imageContainer.image; } - (void)tip_imageFetchOperation:(TIPImageFetchOperation *)op didLoadFirstAnimatedImageFrame:(id<TIPImageFetchResult>)progressiveResult progress:(float)progress { NSLog(@"...animated first frame (%.3f)...", progress); _imageView.image = progressiveResult.imageContainer.image; _progressView.tintColor = [UIColor purpleColor]; [_progressView setProgress:progress animated:YES]; } - (void)tip_imageFetchOperation:(TIPImageFetchOperation *)op didUpdateProgress:(float)progress { NSLog(@"...progress (%.3f)...", progress); [_progressView setProgress:progress animated:YES]; } - (void)tip_imageFetchOperation:(TIPImageFetchOperation *)op didLoadFinalImage:(id<TIPImageFetchResult>)finalResult { NSLog(@"...completed zoom fetch"); _progressView.tintColor = [UIColor greenColor]; [_progressView setProgress:1.f animated:YES]; _imageView.image = finalResult.imageContainer.image; _fetchOp = nil; } - (void)tip_imageFetchOperation:(TIPImageFetchOperation *)op didFailToLoadFinalImage:(NSError *)error { NSLog(@"...failed zoom fetch: %@", error); _progressView.tintColor = [UIColor redColor]; _fetchOp = nil; } @end